#include "myc.h"

void run_regtree(struct tree *tree) {
	setstack(-PTR_SIZE-(tree->type.lv?PTR_SIZE:size(tree->type)));
	struct tree *args=tree->down;
	char *arst=strchr(tree->to.func->name,'(')+1;
	int stcall=stack+PTR_SIZE;
	while (args) {
		if (strcspn(arst,",")>strcspn(arst,"&")) run_tree(args,1);
		else run_tree(args,0);
		args=args->next;
		arst=strchr(arst,',')+1;
	}
	setstack(stcall-stack);
	if (tree->to.func->spe==5) {
		struct vtype typ=tree->type;
		typ.pt--;
		set_param(size(typ));
	}
	if (tree->to.func->spe==3) set_param(size(tree->type));
	call_func(tree->to.func->name);
}

void run_tritree(struct tree *tree) {
	run_tree(tree->down,0);
	pop_cmp(size(tree->down->type));
	int jps=labels+=2;
	jmpn(jps);
	run_tree(tree->down->next,0);
	jmp(jps-1);
	label(jps);
	stack+=size(tree->down->next->type);
	run_tree(tree->down->next->next,0);
	label(jps-1);
}

void run_logtree(struct tree *tree) {
	run_tree(tree->down,0);
	cmp_stack(size(tree->down->type));
	int jps=++labels;
	if (tree->to.func->name[5]=='a') jmpn(jps);
	else jmpp(jps);
	setstack(size(tree->down->type));
	run_tree(tree->down->next,0);
	label(jps);
}

void run_memtree(struct tree *tree) {
	run_tree(tree->down,1);
	set_top(tree->down->next->to.val);
}

void run_simtree(struct tree *tree) {
	switch (tree->toket) {
	case 2:
		push_int(tree->to.val);
		break;
	case 3:
		if (tree->to.var->loc) push_loc(tree->to.var->loc);
		else push_glob(tree->to.var->name);
		break;
	case 4:
		push_char(tree->to.vchar);
		break;
	case 5:
		push_string(tree->to.token);
		break;
	case 1:
		switch (tree->to.func->spe) {
		case 0:
		case 3:
		case 5:
			run_regtree(tree);
			break;
		case 1:
			run_tritree(tree);
			break;
		case 2:
			run_logtree(tree);
			break;
		case 4:
			run_tree(tree->down,0);
			break;
		case 6:
			run_memtree(tree);
			break;
		case 7:
			run_tree(tree->down,1);
			break;
		default:
			treerror(tree,"invalid func type");
		}
		break;
	default:
		treerror(tree,"cannot parse tree");
	}
}

void run_tree(struct tree *tree,int lval) {
	if (lval>tree->type.lv) treerror(tree,"lvalue required");
	if (lval==tree->type.lv) return run_simtree(tree);
	int si=lval?PTR_SIZE:size(tree->type);
	setstack(-PTR_SIZE-si);
	run_tree(tree,lval+1);
	setstack(2*PTR_SIZE);
	set_param(si);
	call_func("operure(same*)");
}
